package Born.photos
{
	import com.greensock.TweenLite;
	
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.ui.Keyboard;
	import flash.utils.clearTimeout;
	import flash.utils.getDefinitionByName;
	import flash.utils.setTimeout;
	
	import Born.events.Events;
	import Born.loader.LoadFile;
	import Born.utils.ScaleDisplay;
	import Born.utils.StageLocation;

	public class FullGallery extends MovieClip
	{
		private var $images						:Array;
		private var $closer						:String;
		private var $box						:MovieClip;
		private var $quit						:MovieClip;
		private var $photo						:MovieClip;
		private var $next						:MovieClip;
		private var $prev						:MovieClip;
		private var $legend						:MovieClip;
		private var $playPause					:MovieClip;
		private var $align						:String;
		private var $rectFull					:Sprite;
		private var $id							:uint;
		private var $imageLoader				:LoadFile;
		private var $imageScaler				:ScaleDisplay;
		private var $imagePercent				:MovieClip;
		private var $imageProgress				:String;
		private var $imageNext					:String;
		private var $imagePrev					:String;
		private var $loaderText					:String;
		private var $imagePlayPause				:String;
		private var $imageLegendClip			:String;
		private var $imageLegend				:Array;
		private var $isLoading					:Boolean;
		private var $isPlaying					:Boolean;
		private var $restoX						:uint;
		private var $restoY						:uint;
		private var $slideTime					:uint;
		private var $slideTimeout				:uint;
		private var $mouseXPercent				:Number;
		private var $mouseYPercent				:Number;
		
		private var topLeftX					:Number;
		private var topLeftY					:Number;
		private var fullWidth					:Number;
		private var fullHeight					:Number;
		
		public function FullGallery(_align:String = "CENTER")
		{
			$align = _align;
			if ( $align != "CENTER" && $align != "LEFT" ) 
			{
				trace("FullGallery precisa receber valor 'CENTER' ou 'LEFT'");
				return void;
			}
			
			$loaderText = "CARREGANDO IMAGEM:";
			$slideTime = 5;
			
			this.addEventListener(Event.ADDED_TO_STAGE, verifyObjects);
			this.addEventListener(Event.REMOVED_FROM_STAGE, removeGallery);
		}
		/**
		 * <b>Adicionando imagens a galeria:</b><br />
		 * mesmo que haja somente uma foto é preciso<br />
		 * mandar em forma de array. 
		 * @param _images : Array - Lista de imagens
		 */		
		public function set addImages(_images:Array):void
		{
			$images = _images;
		}
		/**
		 * <b>Adicionando o carregador das imagens:</b><br />
		 * String da Classe do loader a ser puxada da library.
		 * O Loader deve ter um campo de texto chamado "loadText"
		 * Esse recebera o texto com a porcentagem carregada.
		 * O Texto pode ser alterado usando a função "addLoaderText"
		 * @param _loader : String - Classe do loader
		 */		
		public function set addLoader(_loader:String):void
		{
			$imageProgress = _loader;
		}
		
		public function set addLoaderText(_message:String):void
		{
			$loaderText = _message;
		}
		/**
		 * Adicionando legenda - Colocando um array de legendas
		 * na ordem do array das imagens para sincornizar. 
		 * @param _legend : Array - Legendas na ordem das imagens
		 */		
		public function set addLegend(_legend:Array):void
		{
			$imageLegend = _legend;
		}
		/**
		 * Adicionando o movieclip que contem um campo de texto
		 * que precisa ser chamado de 'legendText' diretamente 
		 * dentro do clip setado. 
		 * @param _legendClip
		 */		
		public function set addLegendClip(_legendClip:String):void
		{
			$imageLegendClip = _legendClip;
		}
		/**
		 * <b>Adicionando o botao de fechar as imagens:</b><br />
		 * Definimos o nome - String - da classe que irá funcionar como botão<br />
		 * de fechar para o FullGallery.
		 * @param _close : String - irá ser convertida em Classe
		 */		
		public function set addClose(_close:String):void
		{
			$closer = _close;
		}
		/**
		 * <b>Adicionando o botao de 'proximo' as imagens:</b><br />
		 * Definimos o nome - String - da classe que irá funcionar como botão<br />
		 * de chamar a proxima imagem do array para o FullGallery.
		 * @param _next : String - irá ser convertida em Classe
		 */		
		public function set addNext(_next:String):void
		{
			$imageNext = _next;
		}
		/**
		 * <b>Adicionando o botao de 'anterior' as imagens:</b><br />
		 * Definimos o nome - String - da classe que irá funcionar como botão<br />
		 * de chamar a imagem anterior do array para o FullGallery.
		 * @param _prev : String - irá ser convertida em Classe
		 */		
		public function set addPrev(_prev:String):void
		{
			$imagePrev = _prev;
		}
		/**
		 * Adicionando o movie clip que vai ser usado com Play e Pause do Slideshow
		 * Para funcionar corretamente esse movieclip precisa ter dois frames
		 * O primeiro com o icone de Play
		 * O segundo com icone de Pause, os dois devidamente parados - stop();
		 * @param _playPause : String - Nome da Class de PlayPause
		 */		
		public function set addPlayPause(_playPause:String):void
		{
			$imagePlayPause = _playPause;
		}
		/**
		 * Setar a quantidade de minutos que irá trocar de uma foto
		 * para a outra, por default o slideshow troca as fotos a cada
		 * cinco segundos depois da foto carregada. 
		 * @param _time : uint - Segundos para SlideShow
		 */		
		public function set addPlayPauseTime(_time:uint):void
		{
			$slideTime = _time;
		}
		/**
		 * Verifica a quantidade e existencia dos objetos para o
		 * funcionamento da galeria, se faltar um deles vai
		 * aparecer uma mensagem ao adicionar a galeria no palco.
		 */		
		private function verifyObjects(e:Event):void
		{
			if ( $images == null ) 
			{
				trace("Error on FullGallery\nError type: Adicionar imagens - addImages(imagens:Array)");
				return void;
			}
			
			if ( $closer == null )
			{
				trace("Error on FullGallery\nError type: Adicionar 'fechar' - addClose(close:String)");
				return void;
			}
			
			if ( $imageProgress == null )
			{
				trace("Error on FullGallery\nError type: Adicionar 'Loader' - addLoader(loader:String)");
				return void;
			}
			
			if ( $imageNext == null )
			{
				trace("Error on FullGallery\nError type: Adicionar 'Next' - addNext(next:String)");
				return void;
			}
			
			if ( $imagePrev == null )
			{
				trace("Error on FullGallery\nError type: Adicionar 'Prev' - addPrev(prev:String)");
				return void;
			}
			
			if ( $imageLegend != null && $imageLegendClip == null )
			{
				trace("Error on FullGallery\nError type: Quando se coloca o array de Legendas é preciso \nsetar também o movieclip da legenda - addLegendClip(legend:String)");
				return void;
			}
		}
		/**
		 * <b>Inicializando, montando e definindo os listeners:</b><br />
		 * Depois de receber as imagens ira mostrar a primeira
		 * e criar a sequencia de imagens para ser mostrada em sequencia 
		 * @param e : Event.ADDED_TO_STAGE
		 */		
		public function initGallery(id:uint = 0):void
		{
			TweenLite.to(this, 0.5, { alpha : 1 });
			
			$box = new MovieClip();
			addChild($box);
			
			$id = id;
			
			// Cria e posiciona o BlackBox
			
			getGalleryPositions();
			
			$imageScaler = new ScaleDisplay();
			
			$rectFull = new Sprite();
			$rectFull.graphics.beginFill(0x000000);
			$rectFull.graphics.drawRect(0, 0, fullWidth, fullHeight);
			$rectFull.graphics.endFill();
			
			$box.alpha = 0;
			$box.x = -topLeftX;
			$box.y = -topLeftY;
			$box.addChild($rectFull);
			TweenLite.to($box, 0.5, { alpha : 1 });
			
			// Movieclip onde vao ser colocadas e removidas as fotos
			
			$photo = new MovieClip;
			$box.addChild($photo);
			
			// Busca o botão na biblioteca e coloca na posicao correta
			
			$quit = new ( getDefinitionByName($closer) as Class )();
			$quit.y = 10;
			$quit.x = fullWidth - ( $quit.width + 10 );
			$quit.buttonMode = true;
			$quit.addEventListener(MouseEvent.CLICK, quitGallery);
			$box.addChild($quit);
			
			
			// Colocando o botao de proxima imagem				
			$next = new ( getDefinitionByName($imageNext) as Class)();
			$next.x = fullWidth - ( $next.width + 10 );
			$next.y = ( fullHeight - $next.height ) * 0.5;
			$next.buttonMode = true;
			$next.addEventListener(MouseEvent.CLICK, ShowNextImage);
			$box.addChild($next);
			
			// Colocando o botao de imagem anteior				
			$prev = new ( getDefinitionByName($imagePrev) as Class)();
			$prev.x = 10;
			$prev.y = ( fullHeight - $prev.height ) * 0.5;
			$prev.buttonMode = true;
			$prev.addEventListener(MouseEvent.CLICK, ShowPrevImage);
			$box.addChild($prev);
			
			// Colocando, se for setado, a legenda
			if ( $imageLegend != null )
			{
				$legend = new ( getDefinitionByName($imageLegendClip) as Class)();
				$legend.y = fullHeight - ( $legend.height + 20 );
				$legend.x = ( fullWidth - $legend.width ) * 0.5;
				$box.addChild($legend);
			}
import flash.events.MouseEvent;

			if ( $imagePlayPause != null )
			{
				$playPause = new ( getDefinitionByName($imagePlayPause) as Class )();
				$playPause.y = fullHeight - ( $playPause.height + 10 );
				$playPause.x = fullWidth - ( $playPause.width + 10 );
				$playPause.buttonMode = true;
				$playPause.addEventListener(MouseEvent.CLICK, ShowSlideShow);
				$box.addChild($playPause);
			}
			
			if ( $images.length == 1 )
			{
				$next.visible = false;
				$prev.visible = false;
				
				if ( $imagePlayPause != null ) $playPause.visible = false;
			}
			
			LoadFullImage($id);
			
			StageLocation.getStage.addEventListener(KeyboardEvent.KEY_DOWN, ChangeGalleryPicture);
			StageLocation.getStage.addEventListener(Event.RESIZE, ResizeFullGallery);
			StageLocation.getStage.addEventListener(MouseEvent.MOUSE_MOVE, MoveFullGallery);
			StageLocation.getStage.addEventListener(MouseEvent.MOUSE_OUT, StopMoveFullGallery);
			StageLocation.getStage.addEventListener(MouseEvent.MOUSE_OVER, PlayMoveFullGallery);
		}
		/**
		 * Função responsavel por carregar e mostrar as imagens
		 * recebidas no array do addImages(); 
		 * @param $id : uint - numero da posicao da imagem no array
		 * 
		 */		
		private function LoadFullImage(_id:uint):void
		{
			var newImage:String = String($images[$id]);
			var newLegend:String = String($imageLegend[$id]);
			// Tentar remover o loader caso ele ja exista
			try { $imageLoader.unload(); }
			catch(e:*){}
			// Cria novamente o loader e chama a imagem da vez.
			$imageLoader = new LoadFile(newImage,true);
			$imageLoader.addEventListener(Events.PROGRESS, LoadingFull);
			$imageLoader.addEventListener(Events.COMPLETE, LoadedFull);
			$imageLoader.addEventListener(Events.IOError, ErrorFull);
			// Cria o loader 
			$imagePercent = new ( getDefinitionByName($imageProgress) as Class )();
			$imagePercent.x = int(( StageLocation.getStageWidth - $imagePercent.width ) * 0.5 );
			$imagePercent.y = int(( StageLocation.getStageHeight - $imagePercent.height ) * 0.5 );
			$imagePercent.alpha = 0;
			TweenLite.to($imagePercent, 0.5, { alpha : 1 });
			$box.addChild($imagePercent);
			
			$photo.x = 0;
			$photo.y = 0;
			TweenLite.to($photo, .5, { alpha : 0 });
			
			if ( $imageLegend != null )
			{
				($legend.LegendBox.legendText as TextField).autoSize = TextFieldAutoSize.LEFT;
				($legend.LegendBox.legendText as TextField).text = newLegend;
				$legend.y = fullHeight - ( $legend.height + 20 );
				$legend.x = ( fullWidth - $legend.width ) * 0.5;
			}
			
			$isLoading = true;
		}
		
		private function LoadingFull(e:Events):void
		{
			var percent:uint = int(e.obj.PercentLoaded);
			
			( $imagePercent.loadText as TextField ).autoSize = TextFieldAutoSize.CENTER;
			( $imagePercent.loadText as TextField ).text = $loaderText + " " + percent + "%";
		}
		
		private function LoadedFull(e:Events):void
		{
			while ( $photo.numChildren != 0 ) $photo.removeChildAt(0);
			
			$box.removeChild($imagePercent);
			
			$photo.alpha = 0;
			$photo.addChild($imageLoader);
			$imageScaler.fill($photo, fullWidth, fullHeight);
			TweenLite.to($photo, 1, { alpha : 1 });
			
			MoveFullGallery(null);
			$isLoading = false;
			if ( $isPlaying ) CallPhotoTimer();
		}
		
		private function ErrorFull(e:Events):void
		{
			throw new Error("Error on FullGallery\nError type: Carregando de imagem falhou\nFile: " + $images[$id]);
			( $imagePercent.loadText as TextField ).autoSize = TextFieldAutoSize.CENTER;
			( $imagePercent.loadText as TextField ).text = "Erro ao carregar imagem, tente mais tarde.";
			
			var nRemove:uint = setTimeout(function():void { $box.removeChild($imagePercent); },2000);
		}
		/**
		 * Funcao que vai verificar posicao da imagem e chamar a proxima
		 * caso seja a ultima irá chamar a primeira dinovo. 
		 * @param e : MouseEvent.CLICK
		 */		
		private function ShowNextImage(e:MouseEvent):void
		{
			StopPhotoTimer();
			if ( $id < ( $images.length - 1 ) )
			{
				$id++;
				LoadFullImage($id);
			}
		}
		/**
		 * Funcao que vai verificar posicao da imagem e chamar a anterior
		 * caso seja a primeira irá chamar a ultima novamente. 
		 * @param e : MouseEvent.CLICK
		 */	
		private function ShowPrevImage(e:MouseEvent):void
		{
			StopPhotoTimer();
			if ( $id > 0 ) 
			{
				$id--;
				LoadFullImage($id);
			}		
		}
		/**
		 * Executa o calculo das posicoes e larguras dos <br />
		 * objetos sempre que executar <br />
		 * ou redimencionar o main Stage 
		 */		
		private function getGalleryPositions():void
		{
			if ( $align == "CENTER" )
			{
				topLeftX 	= ( StageLocation.getStageWidth - StageLocation.getStageWidthFix ) * 0.5;
				topLeftY 	= ( StageLocation.getStageHeight - StageLocation.getStageHeightFix ) * 0.5;
			}
			else
			{
				topLeftX 	= 0;
				topLeftY 	= 0;
			}
			
			fullWidth 	= StageLocation.getStageWidth;
			fullHeight 	= StageLocation.getStageHeight;
		}
		/**
		 * Funcao que irá redimencionar o $box <br />
		 * e movimentar os clips para a nova resolucao <br />
		 * @param e : Event.RESIZE
		 */		
		private function ResizeFullGallery(e:Event):void
		{
			getGalleryPositions();
			
			$box.x = -topLeftX;
			$box.y = -topLeftY;		
			
			if ( !$isLoading )
			{
				$imageScaler.fill($photo, fullWidth, fullHeight);
				TweenLite.to($photo, 0.5, { x : 0, y : 0 });
			}
			else
			{
				$imagePercent.x = int(( StageLocation.getStageWidth - $imagePercent.width ) * 0.5);
				$imagePercent.y = int(( StageLocation.getStageHeight - $imagePercent.height ) * 0.5);
			}
			
			$playPause.y = fullHeight - ( $playPause.height + 10 );
			$playPause.x = fullWidth - ( $playPause.width + 10 );
			
			$legend.y = fullHeight - ( $legend.height + 20 );
			$legend.x = ( fullWidth - $legend.width ) * 0.5;
			
			$quit.y = 10;
			$quit.x = fullWidth - ( $quit.width + 10 );	
			$next.x = fullWidth - ( $next.width + 10 );
			$next.y = ( fullHeight - $next.height ) * 0.5;			
			$prev.x = 10;
			$prev.y = ( fullHeight - $prev.height ) * 0.5;
			
			$rectFull.width = fullWidth;
			$rectFull.height = fullHeight;
		}
		/**
		 * <b>Movimentar a imagem</b><br />
		 * Quando temos imagens muito grandes podemos perder<br />
		 * parte da sua extensão e portanto é necessario que<br />
		 * a imagem tambem move de acordo com o movimento do <br />
		 * Mouse, em X e Y. 
		 * @param e : MouseEvent.MOUSE_MOVE
		 */		
		private function MoveFullGallery(e:MouseEvent):void
		{
			$restoX = int($photo.width - StageLocation.getStageWidth);
			$restoY = int($photo.height - StageLocation.getStageHeight);
			// Percent Mouse Moviment
			$mouseXPercent = Math.ceil(($box.mouseX / StageLocation.getStageWidth) * 100);
			$mouseYPercent = Math.ceil(($box.mouseY / StageLocation.getStageHeight) * 100);
			// Criando enfim o movimento			
			$photo.x = -(( $restoX / 100 ) * $mouseXPercent);
			$photo.y = -(( $restoY / 100 ) * $mouseYPercent);
		}
		/**
		 * <b>Parar o movimentar da imagem</b><br />
		 * Irá para a execução do <code>MoveFullGallery()</code> para
		 * não haver bug quando sair do Browser.
		 * @param e : MouseEvent.MOUSE_OUT
		 */	
		private function StopMoveFullGallery(e:MouseEvent):void
		{
			StageLocation.getStage.removeEventListener(MouseEvent.MOUSE_MOVE, MoveFullGallery);
		}
		/**
		 * <b>Play no movimentar da imagem</b><br />
		 * Irá voltar a execução do <code>MoveFullGallery()</code>
		 * @param e : MouseEvent.MOUSE_OUT
		 */
		private function PlayMoveFullGallery(e:MouseEvent):void
		{
			StageLocation.getStage.addEventListener(MouseEvent.MOUSE_MOVE, MoveFullGallery);
		}
		/**
		 * Ira iniciar o slideshow, a cada determinada quantidade de 
		 * segundos será chamada a próxima foto. 
		 * @param e - MouseEvent.CLICK
		 */		
		private function ShowSlideShow(e:MouseEvent):void
		{
			if ( $isPlaying )
			{
				StopPhotoTimer();
				$isPlaying = false;
				$playPause.gotoAndStop(1);
			}
			else
			{
				CallPhotoTimer();
				$isPlaying = true;
				$playPause.gotoAndStop(2);
			}
		}
		
		private function CallPhotoTimer():void
		{
			$slideTimeout = setTimeout(ShowNextImage,( $slideTime * 1000 ),null);
		}
		
		private function StopPhotoTimer():void
		{
			clearTimeout($slideTimeout);
		}
		/**
		 * Usando as setas < > a galeria irá passar para a proxima e 
		 * imagem anterior. 
		 * @param e - KeybordEvent.KEY_DOWN
		 */		
		private function ChangeGalleryPicture(e:KeyboardEvent):void
		{
			if ( e.keyCode == Keyboard.LEFT ) ShowPrevImage(null);
			if ( e.keyCode == Keyboard.RIGHT ) ShowNextImage(null);
		}
		/**
		 * Essa função sera executada no clicar do botao fechar,
		 * lembrando que a FullGallery pode ser removido a qualquer momento
		 * somente utilizando o removeChild onde você chamou a classe. 
		 * @param e : MouseEvent.CLICK
		 */		
		private function quitGallery(e:MouseEvent):void
		{
			TweenLite.to(this, 0.5, { alpha : 0, onComplete : removeGallery, onCompleteParams : [null] });
		}
		/**
		 * <b>Finalizando a galeria:</b><br />
		 * Remover todos os movieclips criados durante a execução<br />
		 * Remover todos os listeners depois que for fechada 
		 * @param e : Event - Event.REMOVED_FROM_STAGE
		 */		
		private function removeGallery(e:Event):void
		{			
			StopPhotoTimer();
			
			try
			{
				$box.removeChild($imagePercent);
				$box.removeChild($legend);
			}
			catch(e:*) {}
			
			$next.removeEventListener(MouseEvent.CLICK, ShowNextImage);
			$box.removeChild($next);
			
			$prev.removeEventListener(MouseEvent.CLICK, ShowPrevImage);
			$box.removeChild($prev);
			
			$quit.removeEventListener(MouseEvent.CLICK, quitGallery);
			$box.removeChild($quit);
			
			$box.removeChild($photo);
			$box.removeChild($rectFull);
			removeChild($box);
			
			StageLocation.getStage.removeEventListener(Event.RESIZE, ResizeFullGallery);
			StageLocation.getStage.removeEventListener(MouseEvent.MOUSE_MOVE, MoveFullGallery);
			this.removeEventListener(Event.REMOVED_FROM_STAGE, removeGallery);
			this.removeEventListener(Event.ADDED_TO_STAGE, verifyObjects);
		}
		
	} // End Class
	
} // End Package